#pragma once

#include "Plane3d.h"
#include <exception>

namespace Geometry
  {
  // 
  Plane3d::Plane3d(double i_a, double i_b, double i_c, double i_d)
    : m_a(i_a), m_b(i_b), m_c(i_c), m_d(i_d)
    {
    if (m_a == 0 && m_b == 0 && m_c == 0)
      throw std::exception("Plane3d ctor : zero - vector passed as norm vector");
    }

  // by point and norm-vector
  Plane3d::Plane3d(const Point3d& i_point, const Vector3d& i_norm)
    {
    // norming norm vector
    double lng = i_norm.GetLength();
    
    if (lng == 0.0)
      throw std::exception("Plane3d ctor : zero - vector passed as norm vector");
    
    m_a = i_norm[0] / lng;
    m_b = i_norm[1] / lng;
    m_c = i_norm[2] / lng;
    m_d = -(i_point[0] * m_a + i_point[1] * m_b + i_point[2] * m_c);
    }

  // by 3 points
  Plane3d::Plane3d(const Point3d& i_point_1, const Point3d& i_point_2, const Point3d& i_point_3)
    {
    throw std::exception("Plane3d ctor by 3 points: not implemented");
    }

  Vector3d Plane3d::GetNormVector() const
    {
    return Vector3d(m_a, m_b, m_c);
    }

  bool Plane3d::ContainsPoint(const Point3d& i_point) const
    { 
    if (m_a * i_point[0] + m_b*i_point[1] + m_c*i_point[2] + m_d == 0.0)
      return true;
    else
      return false;
    }

  double Plane3d::GetCoefD() const
    {
    return m_d;
    }

  bool operator==(const Plane3d& i_left, const Plane3d& i_right)
    {
    Vector3d norm_left = i_left.GetNormVector();
    Vector3d norm_right = i_right.GetNormVector();
    
    if ((norm_left^norm_right).GetLength() != 0.0)
      return false;

    Point3d test_point;
    if (norm_left[0] != 0)
      {
      test_point = Point3d(-i_left.GetCoefD() / norm_left[0], 0.0, 0.0);
      }
    else if (norm_left[1] != 0)
      {
      test_point = Point3d(0.0, -i_left.GetCoefD() / norm_left[1], 0.0);
      }
    else if (norm_left[2] != 0)
      {
      test_point = Point3d(0.0, 0.0, -i_left.GetCoefD() / norm_left[2]);
      }
    else
      {
      throw std::exception("Plane3d operator == got invalid Plane3d arg");
      }

    if (i_right.ContainsPoint(test_point))
      return true;
    else
      return false;

    }
  }